iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 1
0
自我挑戰組

IT文章簡介(Medium)系列 第 1

(翻譯)Here’s how you can make better use of JavaScript arrays

  • 分享至 

  • xImage
  •  

Source:Here’s how you can make better use of JavaScript arrays

原作同意翻譯的連結


快速閱讀,我保證。過去幾個月裡,我注意我檢查過的pull requests仍然存在相同的四個錯誤,我貼這篇文章也是因為我自己犯了這些錯誤!讓我們瀏覽這些問題確保我們正確使用Array方法。

用Array.includes替換Array.indexOf

「如果你在陣列中尋找一些東西,請使用Array.indexOf。」我記得在學習JavaScript的過程中讀過這樣一句話。 這句話是真的,不用懷疑!

MDN文件說Array.indexOf返回找到的元素的第一個索引,因此如果稍後我們在程式碼中使用返回索引Array.indexOf就是解決方案。

但是如果我們只需要知道我們的陣列是否包含某值呢?這是一個是/否的問題,一個boolean問題。這種情況我建議使用返回boolean的Array.includes。

'use strict';

const characters = [
  'ironman',
  'black_widow',
  'hulk',
  'captain_america',
  'hulk',
  'thor',
];

console.log(characters.indexOf('hulk'));
// 2
console.log(characters.indexOf('batman'));
// -1

console.log(characters.includes('hulk'));
// true
console.log(characters.includes('batman'));
// false

使用Array.find而不是Array.filter

Array.filter是一個非常有用的方法。它存另一個陣列創建一個所有項目的通過回調參數的新陣列。正如其名,我們必須使用此方法進行過濾並得到更短的陣列。

但是,假如我們知道我們的回調函數只返回一個項目,我就不推薦它 — 例如,使用回調函數透過唯一的ID過濾。這種情況下,Array.filter返回一個只有一個項目的陣列。尋找特定ID,我們的意圖可能是使用這個陣列所包含的唯一的值,這個陣列是沒有用的。

談論性能。返回所有符合回調函數的項目,Array.filter必須瀏覽整個陣列。而且,我們假設有幾百個項目符合我們的回調函數,我們過濾的陣列是非常大的。

避免這種情況,我建議使用Array.find。它需要像Array.filter一樣的回調函數,並返回滿足條件的第一個元素。而且只要一滿足條件,Array.find就會停止,無需瀏覽整個陣列。此外,通過Array.find尋找項目,我們可以更清楚了解我們的意圖。

'use strict';

const characters = [
  { id: 1, name: 'ironman' },
  { id: 2, name: 'black_widow' },
  { id: 3, name: 'captain_america' },
  { id: 4, name: 'captain_america' },
];

function getCharacter(name) {
  return character => character.name === name;
}

console.log(characters.filter(getCharacter('captain_america')));
// [
//   { id: 3, name: 'captain_america' },
//   { id: 4, name: 'captain_america' },
// ]

console.log(characters.find(getCharacter('captain_america')));
// { id: 3, name: 'captain_america' }

用Array.some替換Array.find

我承認我犯過很多次這個錯誤。一個善良的朋友告訴我MDN文件可以找到更好的方法。這件事情跟上面的Array.indexOf / Array.includes案例很像。

上一個案例,Array.find需要一個回調參數並返回一個元素。假如我們需要知道我們的陣列是否包含值,Array.find是最好的解決方案嗎?可能不是,因為它返回一個值而不是boolean。

這種情況我建議使用Array.some,它返回boolean。另外在語義上,使用Array.some凸顯我們不需要找到項目。

'use strict';

const characters = [
  { id: 1, name: 'ironman', env: 'marvel' },
  { id: 2, name: 'black_widow', env: 'marvel' },
  { id: 3, name: 'wonder_woman', env: 'dc_comics' },
];

function hasCharacterFrom(env) {
  return character => character.env === env;
}

console.log(characters.find(hasCharacterFrom('marvel')));
// { id: 1, name: 'ironman', env: 'marvel' }

console.log(characters.some(hasCharacterFrom('marvel')));
// true

使用Array.reduce而不是鏈接Array.filter和Array.map

讓我們面對它,Array.reduce不易理解。這是真的!但是,如果我們運行Array.filter然後再Array.map,感覺好像我們錯過了什麼,對吧?

我的意思是,我們瀏覽陣列兩次。第一次過濾並創建一個較短的陣列,第二次創建一個基於Array.filter的新陣列(再次!)。為了得到新陣列,用了兩種Array方法,每個方法都有自己的回調函數和一個我們之後都不會使用的陣列(由Array.filter創建的)。

避免這種低效,我建議使用Array.reduce。一樣的結果,更好的Code! Array.reduce允許我們過濾且把滿足條件的項目加到累加器(accumulator)中。例如,累加器可以是數字的累加、物件的填充、字串或陣列的連接。

在我們的例子中,我們一直使用Array.map,我建議使用帶有陣列的Array.reduce作為累加器進行連接。下面的例子,根據env的值決定是否將項目加入累加器。

'use strict';

const characters = [
  { name: 'ironman', env: 'marvel' },
  { name: 'black_widow', env: 'marvel' },
  { name: 'wonder_woman', env: 'dc_comics' },
];

console.log(
  characters
    .filter(character => character.env === 'marvel')
    .map(character => Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
);
// [
//   { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
//   { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]

console.log(
  characters
    .reduce((acc, character) => {
      return character.env === 'marvel'
        ? acc.concat(Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
        : acc;
    }, [])
)
// [
//   { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
//   { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]

就這樣,完成!

希望有幫助。 如果您對本文有任何想法或有任何其他案例要顯示,請務必留下評論。 如果你發現它有用,請給原作一些鼓掌?並分享。 謝謝閱讀!


原文下方的評論:

  • 可疑的文章:現時情況會使用大量的資料進行操作,物件陣列可能會包含一些相同名字的項目,這時應該處理每一個項目,而不是群組中的特定一個。因此我認為indexOf →includes 和 find →filter是有幫助的。
  • 如果要在物件陣列中尋找有特定屬性值的物件的位置,可以用.findIndex比起先.map後.indexOf的鏈結更好。
  • 如果用簡單的console.time()測試,.filter() & .map()的性能比.reduce更好
  • 最後一個範例感覺不乾淨俐落,可以使用transducer。
  • 最後一個案例要改良
  • 落落長的Big O性能解釋Array方法
  • 可讀性
  • IE和一些舊瀏覽器不支援Array.includes 和 Array.find
  • // NaN will not be deducted by indexOf
    const res = [NaN].indexOf(NaN);
    console.log(res); // -1
    console.log([NaN].includes(NaN)); // true
  • 要注意瀏覽器有沒有支援這些Array方法
  • 有驗證性能嗎?
  • Array.prototype.includes() 是 ES7 的功能
  • 某些情況下.filter和.map在可讀性、程式碼分離、程式碼重用方面更好。

下一篇
(翻譯)I created the exact same app in React and Vue. Here are the differences.
系列文
IT文章簡介(Medium)5
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言